package locks;

import java.util.concurrent.atomic.AtomicReference;

public class MCSLock implements SimpleLock {

    private AtomicReference<QNode> tail;

    private ThreadLocal<QNode> myNode;

    public MCSLock() {
        this.tail = new AtomicReference<>(null);
        this.myNode = ThreadLocal.withInitial(QNode::new);
    }

    @Override
    public void lock() {
        QNode qNode = myNode.get();
        QNode pred = tail.getAndSet(qNode);
        if (pred != null) {
            qNode.locked = true;
            pred.next = qNode;
            while (qNode.locked) {
            }
        }
    }

    @Override
    public void unlock() {
        QNode qNode = myNode.get();
        if (qNode.next == null) {

            if (tail.compareAndSet(qNode, null)) {
                return;
            }
            while (qNode.next == null) {
            }
        }
        qNode.next.locked = false;
        qNode.next = null;
    }

    private class QNode {
        private volatile boolean locked;
        private volatile QNode next;
    }
}
